/**
 * ============验证码数据模型模块开始===========
 * 验证码数据模型 - Verification Code Data Model
 * 
 * 功能说明：
 * - 管理各种类型的验证码（短信、邮箱等）
 * - 提供验证码的创建、验证和状态管理
 * - 支持验证码过期时间控制
 * - 防止验证码重复使用
 * - 支持多种验证场景（注册、登录、找回密码等）
 * 
 * 依赖模块：
 * - dayjs: 现代化的日期时间处理库，用于时间计算和格式化
 * - nanoid: 生成唯一ID的轻量级库，用于创建验证码记录ID
 * - database: 本地JSON数据库实例，提供数据持久化
 * 
 * 数据结构：
 * VerificationCode对象包含以下字段：
 * - id: 验证码记录的唯一标识符
 * - target: 验证目标（手机号或邮箱地址）
 * - code: 验证码内容（通常是4-6位数字）
 * - type: 验证码类型（sms/email/register/login/reset等）
 * - expiresAt: 过期时间（ISO格式字符串）
 * - used: 是否已使用（防止重复使用）
 * - createdAt: 创建时间（ISO格式字符串）
 * 
 * 安全特性：
 * - 验证码有效期控制（默认5分钟）
 * - 一次性使用机制（使用后自动标记为已用）
 * - 支持不同类型的验证码隔离
 * - 自动过期检查机制
 * 
 * 应用场景：
 * - 用户注册验证
 * - 登录二次验证
 * - 找回密码验证
 * - 敏感操作确认
 * - 手机号/邮箱绑定验证
 * 
 * 设计原则：
 * - 安全性优先：严格的过期和使用控制
 * - 灵活性：支持多种验证码类型和场景
 * - 可扩展性：易于添加新的验证类型
 * - 性能优化：高效的查询和状态管理
 * 
 * Provides comprehensive verification code management with security features
 */

// 导入必要的依赖包 - Import necessary dependencies
import dayjs from "dayjs";                    // 日期时间处理库 - Date/time manipulation library
import { nanoid } from "nanoid";              // 唯一ID生成器 - Unique ID generator
import { db } from "../data/database.js";     // 数据库实例 - Database instance

/**
 * 验证码数据模型类 - Verification Code Data Model Class
 * 
 * 该模型封装了所有与验证码相关的数据库操作
 * 提供了完整的验证码生命周期管理功能
 * 
 * 设计原则：
 * - 单一职责：只处理验证码相关的数据操作
 * - 安全性：严格的过期时间和使用状态控制
 * - 一致性：提供统一的异步接口
 * - 可靠性：完善的错误处理和日志记录
 * - 性能：优化的查询和存储策略
 */
export const VerificationModel = {
  /**
   * ============创建验证码功能开始===========
   * 创建新的验证码记录
   * Create new verification code record
   * 
   * @param {Object} params - 验证码创建参数
   * @param {string} params.target - 验证目标（手机号或邮箱）
   * @param {string} params.code - 验证码内容
   * @param {string} params.type - 验证码类型（sms/email/register/login/reset等）
   * @param {number} params.expiresInMinutes - 过期时间（分钟，默认5分钟）
   * @returns {Promise<Object>} 创建的验证码记录对象
   * @throws {Error} 当创建失败时抛出异常
   * 
   * 功能说明：
   * - 创建新的验证码记录并保存到数据库
   * - 自动生成唯一的记录ID
   * - 设置验证码的过期时间
   * - 初始化验证码状态（未使用）
   * - 记录创建时间用于审计
   * 
   * 验证码类型说明：
   * - 'sms': 短信验证码
   * - 'email': 邮箱验证码
   * - 'register': 注册验证
   * - 'login': 登录验证
   * - 'reset': 密码重置
   * - 'bind': 绑定操作
   * 
   * 使用场景：
   * - 用户注册时发送验证码
   * - 登录时的二次验证
   * - 找回密码流程
   * - 绑定新手机号或邮箱
   * 
   * 使用示例：
   * const record = await VerificationModel.createCode({
   *   target: '13800138000',
   *   code: '123456',
   *   type: 'register',
   *   expiresInMinutes: 10
   * });
   * console.log('验证码创建成功:', record.id);
   * 
   * 异常处理：
   * - 参数验证失败
   * - 数据库写入失败
   * - 时间计算错误
   * 
   * 安全考虑：
   * - 验证码不应在日志中明文记录
   * - 过期时间应合理设置（不宜过长）
   * - 支持验证码发送频率限制
   */
  async createCode({ target, code, type, expiresInMinutes = 5 }) {
    try {
      // 第一步：参数验证 - Step 1: Parameter validation
      if (!target) {
        throw new Error('验证目标不能为空 - Target cannot be empty');
      }
      
      if (!code) {
        throw new Error('验证码不能为空 - Code cannot be empty');
      }
      
      if (!type) {
        throw new Error('验证码类型不能为空 - Type cannot be empty');
      }
      
      // 验证过期时间范围 - Validate expiration time range
      if (expiresInMinutes < 1 || expiresInMinutes > 60) {
        throw new Error('过期时间应在1-60分钟之间 - Expiration time should be between 1-60 minutes');
      }
      
      // 第二步：读取数据库 - Step 2: Read database
      await db.read();
      
      // 第三步：构建验证码记录 - Step 3: Build verification code record
      const record = {
        id: nanoid(),                                                    // 生成唯一ID - Generate unique ID
        target,                                                          // 验证目标 - Verification target
        code,                                                            // 验证码内容 - Verification code
        type,                                                            // 验证码类型 - Verification type
        expiresAt: dayjs().add(expiresInMinutes, "minute").toISOString(), // 计算过期时间 - Calculate expiration time
        used: false,                                                     // 初始状态为未使用 - Initial state: unused
        createdAt: new Date().toISOString(),                             // 记录创建时间 - Record creation time
      };
      
      // 第四步：保存到数据库 - Step 4: Save to database
      db.data.verificationCodes.push(record);
      await db.write();
      
      // 第五步：记录日志（不包含验证码内容） - Step 5: Log (without code content)
      console.log(`验证码创建成功 - Verification code created successfully: ${record.id}, type: ${type}, target: ${target}`);
      
      return record;
      
    } catch (error) {
      // 第六步：错误处理 - Step 6: Error handling
      console.error('创建验证码失败 - Failed to create verification code:', error);
      throw new Error(`创建验证码失败: ${error.message}`);
    }
  },

  /**
   * ============验证码验证功能开始===========
   * 验证验证码的有效性
   * Verify the validity of verification code
   * 
   * @param {Object} params - 验证参数
   * @param {string} params.target - 验证目标（手机号或邮箱）
   * @param {string} params.code - 用户输入的验证码
   * @param {string} params.type - 验证码类型
   * @returns {Promise<Object|null>} 有效的验证码记录或null
   * @throws {Error} 当验证过程失败时抛出异常
   * 
   * 功能说明：
   * - 查找匹配的验证码记录
   * - 检查验证码是否已过期
   * - 检查验证码是否已被使用
   * - 返回有效的验证码记录或null
   * 
   * 验证条件：
   * - 目标匹配（target相同）
   * - 验证码匹配（code相同）
   * - 类型匹配（type相同）
   * - 未被使用（used为false）
   * - 未过期（当前时间小于expiresAt）
   * 
   * 使用场景：
   * - 用户提交验证码时的验证
   * - 注册流程中的验证码确认
   * - 登录二次验证
   * - 密码重置验证
   * 
   * 使用示例：
   * const record = await VerificationModel.verifyCode({
   *   target: '13800138000',
   *   code: '123456',
   *   type: 'register'
   * });
   * 
   * if (record) {
   *   console.log('验证码有效');
   *   // 继续后续业务逻辑
   * } else {
   *   console.log('验证码无效或已过期');
   * }
   * 
   * 异常处理：
   * - 参数验证失败
   * - 数据库读取失败
   * - 时间比较错误
   * 
   * 安全特性：
   * - 严格的多条件匹配
   * - 自动过期检查
   * - 防止重复使用
   * - 类型隔离验证
   */
  async verifyCode({ target, code, type }) {
    try {
      // 第一步：参数验证 - Step 1: Parameter validation
      if (!target) {
        throw new Error('验证目标不能为空 - Target cannot be empty');
      }
      
      if (!code) {
        throw new Error('验证码不能为空 - Code cannot be empty');
      }
      
      if (!type) {
        throw new Error('验证码类型不能为空 - Type cannot be empty');
      }
      
      // 第二步：读取数据库 - Step 2: Read database
      await db.read();
      
      // 第三步：查找匹配的验证码记录 - Step 3: Find matching verification code record
      // 使用多条件匹配确保验证码的准确性和安全性
      const record = db.data.verificationCodes.find((item) => {
        return (
          item.target === target &&                    // 目标匹配 - Target matches
          item.code === code &&                        // 验证码匹配 - Code matches
          item.type === type &&                        // 类型匹配 - Type matches
          !item.used &&                                // 未被使用 - Not used
          dayjs(item.expiresAt).isAfter(dayjs())       // 未过期 - Not expired
        );
      });
      
      // 第四步：返回结果 - Step 4: Return result
      if (record) {
        console.log(`验证码验证成功 - Verification code verified successfully: ${record.id}`);
        return record;
      } else {
        console.log(`验证码验证失败 - Verification code verification failed: target=${target}, type=${type}`);
        return null;
      }
      
    } catch (error) {
      // 第五步：错误处理 - Step 5: Error handling
      console.error('验证码验证过程失败 - Verification code verification process failed:', error);
      throw new Error(`验证码验证失败: ${error.message}`);
    }
  },

  /**
   * ============标记验证码已使用功能开始===========
   * 标记验证码为已使用状态
   * Mark verification code as used
   * 
   * @param {string} id - 验证码记录ID
   * @returns {Promise<boolean>} 标记是否成功
   * @throws {Error} 当标记失败时抛出异常
   * 
   * 功能说明：
   * - 将指定的验证码记录标记为已使用
   * - 防止验证码被重复使用
   * - 确保验证码的一次性特性
   * - 更新数据库状态
   * 
   * 使用场景：
   * - 验证码验证成功后立即调用
   * - 确保验证码只能使用一次
   * - 维护验证码的安全性
   * 
   * 使用示例：
   * const record = await VerificationModel.verifyCode({...});
   * if (record) {
   *   // 验证成功，标记为已使用
   *   await VerificationModel.markUsed(record.id);
   *   // 继续业务逻辑
   * }
   * 
   * 异常处理：
   * - 记录ID不存在
   * - 数据库写入失败
   * 
   * 安全考虑：
   * - 确保验证码只能使用一次
   * - 防止重放攻击
   * - 维护验证码状态的一致性
   */
  async markUsed(id) {
    try {
      // 第一步：参数验证 - Step 1: Parameter validation
      if (!id) {
        throw new Error('验证码记录ID不能为空 - Verification code record ID cannot be empty');
      }
      
      // 第二步：读取数据库 - Step 2: Read database
      await db.read();
      
      // 第三步：查找验证码记录 - Step 3: Find verification code record
      const record = db.data.verificationCodes.find((item) => item.id === id);
      
      if (record) {
        // 第四步：标记为已使用 - Step 4: Mark as used
        record.used = true;
        record.usedAt = new Date().toISOString(); // 记录使用时间 - Record usage time
        
        // 第五步：保存到数据库 - Step 5: Save to database
        await db.write();
        
        console.log(`验证码标记为已使用 - Verification code marked as used: ${id}`);
        return true;
      } else {
        console.warn(`验证码记录不存在 - Verification code record not found: ${id}`);
        return false;
      }
      
    } catch (error) {
      // 第六步：错误处理 - Step 6: Error handling
      console.error('标记验证码已使用失败 - Failed to mark verification code as used:', error);
      throw new Error(`标记验证码失败: ${error.message}`);
    }
  },

  /**
   * ============清理过期验证码功能开始===========
   * 清理过期的验证码记录
   * Clean up expired verification code records
   * 
   * @returns {Promise<number>} 清理的记录数量
   * @throws {Error} 当清理失败时抛出异常
   * 
   * 功能说明：
   * - 删除所有已过期的验证码记录
   * - 释放数据库存储空间
   * - 提高查询性能
   * - 维护数据库整洁
   * 
   * 使用场景：
   * - 定时任务清理
   * - 系统维护
   * - 性能优化
   * 
   * 使用示例：
   * const cleanedCount = await VerificationModel.cleanExpired();
   * console.log(`清理了 ${cleanedCount} 条过期记录`);
   */
  async cleanExpired() {
    try {
      // 第一步：读取数据库 - Step 1: Read database
      await db.read();
      
      // 第二步：获取当前时间 - Step 2: Get current time
      const now = dayjs();
      
      // 第三步：筛选未过期的记录 - Step 3: Filter non-expired records
      const originalCount = db.data.verificationCodes.length;
      db.data.verificationCodes = db.data.verificationCodes.filter(item => 
        dayjs(item.expiresAt).isAfter(now)
      );
      
      // 第四步：计算清理数量 - Step 4: Calculate cleaned count
      const cleanedCount = originalCount - db.data.verificationCodes.length;
      
      // 第五步：保存到数据库 - Step 5: Save to database
      if (cleanedCount > 0) {
        await db.write();
        console.log(`清理过期验证码成功 - Expired verification codes cleaned successfully: ${cleanedCount} records`);
      }
      
      return cleanedCount;
      
    } catch (error) {
      // 第六步：错误处理 - Step 6: Error handling
      console.error('清理过期验证码失败 - Failed to clean expired verification codes:', error);
      throw new Error(`清理过期验证码失败: ${error.message}`);
    }
  }
};
